#include "stdafx.h"
#include "proc.h"
#include "thread.h"
#include "kernel.h"

namespace xm
{
	long process_t::_handle_page_fault( thread_t * to, uint64_t addr, size_t code )
	{
		if( addr >= vms.top_address() )
			return (EXCEPTION_ACCESS_VIOLATION);

		long lr = 0;

		//printf( "handle_page_fault( %I64X, %X )\n", addr, code );
		uint64_t pba = addr & ~0xFFFLL;

		vmarea_t * area = vms.find( pba, -1 );
		if( !area )
			return (EXCEPTION_ACCESS_VIOLATION);

		void * fastcc = 0;
		uint32_t paga = paga_get( pba, area, &fastcc );

		if( paga & PGA_GUARD )
			return (EXCEPTION_GUARD_PAGE);

		if( !paga || (paga&PGA_REVERSE) || !(paga&PGPROT_MASK) )
			return (EXCEPTION_ACCESS_VIOLATION);

		rmb_t * rmb = 0;
		if( code & x64::PF_WRITE )
		{
			rmb = _page_get_to_write( area, pba, true, &paga );
		}
		else
		{
			rmb = _page_get_to_read( area, pba );
		}
		
		if( !rmb )
			return (EXCEPTION_ACCESS_VIOLATION);

		void * ldp = rmb_lock(rmb);
		if( !ldp )
			return (EXCEPTION_ACCESS_VIOLATION);

		if( fastcc )
			lr = pgt.vmmap( (x64::_4k::pte_t*)fastcc, rmb_pma(rmb), paga|PGA_COMMIT );
		else
			lr = pgt.vmmap( pba, rmb_pma(rmb), paga|PGA_COMMIT );

		rmb_unlock(rmb);
		
		if( lr < 0 )
			return (EXCEPTION_ACCESS_VIOLATION);

		if( is_current_process() )
			vx64_flush_tlb( pba );

		return S_OK;
	}

	enum 
	{
		API_VirtualAlloc = 0x00010007,
		API_VirtualFree = 0x00010008,
		API_SetLasError = 0x000100010,
	};

	//	ret
	//	apiid
	//	arg1
	//	arg2
	//	arg3
	
	long process_t::_handle_syscall( thread_t * to )
	{
		vxlong_t apiid = 0;
		to->_rt_get_stack( 1, apiid );
		if( apiid == API_VirtualAlloc )
		{
			uint32_t args[4];
			to->_rt_get_stack( 2, args, 4 );
			vxvma_t bas = args[0];
			uint32_t paga = alloctype_to_paga( args[2], 0 );
			paga = prot_to_paga( args[3], paga );
			RFAILED( vms_alloc( &bas, args[1], paga ) );
			vx64_set_reg( VXR_EAX, bas );
		}
		return 0;
	}

};